package com.chaintor.demo.math;

import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiableFunction;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.util.FastMath;

/**
 * delta转换成deltaSimple的函数，需要用牛顿迭代求值
 */
public class DeltaToDeltaSimpleFunction implements UnivariateDifferentiableFunction{
    private NormalDistribution normal = new NormalDistribution();
    private DeltaSimpleFunction dsf;
    private double sqrtT;
    private double nicpDelta;

    public DeltaToDeltaSimpleFunction(DeltaSimpleFunction dsf,double delta,double te_to_t){
        this.nicpDelta = normal.inverseCumulativeProbability(delta);
        this.dsf = dsf;
        this.sqrtT = FastMath.sqrt(te_to_t/365.0);
    }

    public DerivativeStructure value(DerivativeStructure t) throws DimensionMismatchException {
        double x = t.getValue();
        double y = this.value(x);
        double dy = ddvalue(x);
        return new DerivativeStructure(1,1,y,dy);
    }

    public double value(double x) {
        return normal.inverseCumulativeProbability(x)-nicpDelta+0.5*dsf.value(x)*sqrtT;
    }

    /**
     * 近似的导数求解
     * @param v
     * @return
     */
    private double dvalue(double v){
        double y0 = this.value(v+1E-10);
        double y1 = this.value(v-1E-10);

        return (y0-y1)/(2*1E-10);
    }

    /**
     * 精确的导数求解
     * @param v
     * @return
     */
    private double ddvalue(double v){
        double density = 1.0/normal.density(normal.inverseCumulativeProbability(v));
        return density+0.5*sqrtT*dsf.dvalue(v);
    }
}
